//==============================================================================
// Copyright (c) 2008-2013 Niall Ryan. All Rights Reserved.
//==============================================================================

#ifndef HYDRA_TYPETRAITS_H
#define HYDRA_TYPETRAITS_H 1

#define HYDRA_TYPETRAITS_DECLARE(trait, b)	\
	template<typename T>					\
	struct trait							\
	{										\
		static const bool value = b;		\
	}

#define HYDRA_TYPETRAITS_SPECIALIZE(trait, type, b)	\
	template<>										\
	struct trait<type>								\
	{												\
		static const bool value = b;				\
	}

namespace Hydra
{
	namespace TypeTraits
	{
		namespace Internal
		{
			template<bool b1, bool b2, bool b3=false, bool b4=false, bool b5=false, bool b6=false, bool b7=false, bool b8=false>
			struct TraitsOr
			{
				static const bool value = true;
			};
			template<>
			struct TraitsOr<false, false, false, false, false, false, false, false>
			{
				static const bool value = false;
			};
		}

		HYDRA_TYPETRAITS_DECLARE(is_integral, false);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, char, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, short, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, int, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, long, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, unsigned char, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, unsigned short, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, unsigned int, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_integral, unsigned long, true);

		HYDRA_TYPETRAITS_DECLARE(is_floating_point, false);
		HYDRA_TYPETRAITS_SPECIALIZE(is_floating_point, float, true);
		HYDRA_TYPETRAITS_SPECIALIZE(is_floating_point, double, true);

		HYDRA_TYPETRAITS_DECLARE(is_void, false);
		HYDRA_TYPETRAITS_SPECIALIZE(is_void, void, true);

		template<typename T> struct is_fundamental : public Internal::TraitsOr<is_integral<T>::value, is_floating_point<T>::value, is_void<T>::value>	{ };

		template<typename T> struct has_trivial_constructor : public Internal::TraitsOr<is_fundamental<T>::value, __has_trivial_constructor(T)>	{ };
		template<typename T> struct has_trivial_destructor : public Internal::TraitsOr<is_fundamental<T>::value, __has_trivial_destructor(T)>	{ };
	}
}

#undef HYDRA_TYPETRAITS_DECLARE
#undef HYDRA_TYPETRAITS_SPECIALIZE

#endif
